package torres.controller;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.List;

import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;

import torres.RunGame;
import torres.entity.Ability;
import torres.entity.Avatar;
import torres.entity.Entity;
import torres.fileIO.Saver;
import torres.item.*;
import torres.map.Location;
import torres.map.Map;
import torres.map.World;
import torres.map.tile.Tile;
import torres.view.AreaViewPort;
import torres.view.AsciiAreaViewPort;
import torres.view.MainView;
import torres.view.StatusViewPort;

/**
 * @author Torres
 * The Controller in the MVC architecture; parses keyboard 
 * and mouse input and issues the appropriate commands.
 */
public class Controller implements KeyListener, MouseListener {

	private static JPanel inventory;
	private static JLabel[] equipInventory;
	private static JPanel abilities;
	private static JLayeredPane layerPane;
	private static MainView mainView;
	private static AreaViewPort twoD, ascii;
	private Ability ability = null;
	private Entity entity = null;
	
	/**
	 * Controller constructor creates the controller instance that relays user input and dispatches commands
	 * as needed.
	 */
	private Controller() {
		inventory = null;
		equipInventory = null;
		mainView = null;
		ascii = new AsciiAreaViewPort();
	}
	
	/**
	 * Adds a KeyListener to the given Component passed.  By convention Component should superclass MainView.
	 * @param main the Component that wants to add KeyListener
	 */
	public static void addKeyListener(MainView main) {
		
		mainView = main;
		mainView.getAreaViewPort().getArea().addKeyListener(new Controller());
	}
	
	/**
	 * Adds a MouseListener to the given Component passed.  By convention Component should superclass MainView.
	 * @param main the main component that wants to add MouseListener
	 */
	public static void addMouseListener(MainView main) {
		
		Controller c = new Controller();
		mainView = main;
		twoD = main.getAreaViewPort();
		AreaViewPort avp = mainView.getAreaViewPort();
		avp.getArea().addMouseListener(c);
		StatusViewPort svp = mainView.getStatusViewPort();
		inventory = svp.getInventory();
		equipInventory = svp.getEquipInventory();
		abilities = svp.getAbilities();
		layerPane = avp.getLayerPane();
		@SuppressWarnings("unused")
		Map map = World.getInstance().getCurrentMap();
		for(int i = 0; i < 25; i++) {
			layerPane.getComponent(i).addMouseListener(c);
		}
		for(int i=0; i < 15; i++) {
			svp.getInventory().getComponent(i).addMouseListener(c);
		}
		for(int i=0; i < 5; i++) {
			equipInventory[i].addMouseListener(c);
		}
		int size = World.getInstance().getCurrentMap().getAvatar().getOccupation().getAbilityList().size();
		for(int i = 0; i < size; ++i) {
			abilities.getComponent(i).addMouseListener(c);
		}
	}
	
	/* (non-Javadoc)
	 * @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent)
	 */
	@Override
	public void keyPressed(KeyEvent arg0) {
		
		int key = arg0.getKeyCode();
		Map map = World.getInstance().getCurrentMap();
		Entity avatar = map.getAvatar();
			
		if(key == KeyEvent.VK_NUMPAD8 || key == KeyEvent.VK_UP) {	//Move NORTH
			Command.moveEntity(Direction.NORTH, avatar);
			//Command.moveEntity(, entity)
			//RunGame.map.addEntity(new Location(2, 2), RunGame.player);
			//System.out.println("I MOVED UP!");
			
		}
		if(key == KeyEvent.VK_NUMPAD9) {	//Move NORTHEAST
			Command.moveEntity(Direction.NORTHEAST, avatar);
			
			//RunGame.map.addEntity(new Location(2, 2), RunGame.player);
			//System.out.println("I MOVED UP!");
			
		}
		if(key == KeyEvent.VK_NUMPAD6 || key == KeyEvent.VK_RIGHT) {	//Move EAST
			Command.moveEntity(Direction.EAST, avatar);
			//RunGame.map.addEntity(new Location(3, 2), RunGame.player);
			
		}
		if(key == KeyEvent.VK_NUMPAD3) {	//Move SOUTHEAST
			Command.moveEntity(Direction.SOUTHEAST, avatar);
			//RunGame.map.addEntity(new Location(2, 2), RunGame.player);
			//System.out.println("I MOVED UP!");
			
		}
		if(key == KeyEvent.VK_NUMPAD2 || key == KeyEvent.VK_DOWN) {	//Move SOUTH
			Command.moveEntity(Direction.SOUTH, avatar);
			//RunGame.map.addEntity(new Location(2, 3), RunGame.player);
			
		}
		if(key == KeyEvent.VK_NUMPAD1) {	//Move SOUTHWEST
			Command.moveEntity(Direction.SOUTHWEST, avatar);
			//RunGame.map.addEntity(new Location(1, 2), RunGame.player);
			
		}
		if(key == KeyEvent.VK_NUMPAD4 || key == KeyEvent.VK_LEFT) {	//Move WEST
			Command.moveEntity(Direction.WEST, avatar);
			//RunGame.map.addEntity(new Location(3, 2), RunGame.player);
			
		}
		if(key == KeyEvent.VK_NUMPAD7) {	//Move NORTHWEST
			Command.moveEntity(Direction.NORTHWEST, avatar);
			//RunGame.map.addEntity(new Location(3, 2), RunGame.player);
		}
		
		if(key == KeyEvent.VK_F5) {
			Saver.save("save1.sav");
		}
		
		if(key == KeyEvent.VK_F8) {
			RunGame.load = true;
		}
		
		if(key == KeyEvent.VK_Z) {
			
			Command.addExperience(avatar);
		}
		
		if(key == KeyEvent.VK_F12 || key == KeyEvent.VK_Q) {
			if(mainView.getAreaViewPort().isTwoD()) 
				mainView.setAreaViewPort(ascii);
			
			else if (mainView.getAreaViewPort().isAscii()) 
				mainView.setAreaViewPort(twoD);
			
			mainView.getAreaViewPort().getArea().addKeyListener(this);
		} 
	}

	/* (non-Javadoc)
	 * @see java.awt.event.KeyListener#keyReleased(java.awt.event.KeyEvent)
	 */
	@Override
	public void keyReleased(KeyEvent arg0) {
		
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see java.awt.event.KeyListener#keyTyped(java.awt.event.KeyEvent)
	 */
	@Override
	public void keyTyped(KeyEvent arg0) {
		
		// TODO Auto-generated method stub

	}
	
	/* (non-Javadoc)
	 * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent)
	 */
	@Override
	public void mouseClicked(MouseEvent arg0) {
		Map map = World.getInstance().getCurrentMap();
		Avatar avatar = map.getAvatar();

		List<TakeableItem> avatarInventory = avatar.getInventory().getItemList();
		List<Ability> abilitiesList = avatar.getOccupation().getAbilityList();
		JLabel jl = (JLabel) arg0.getComponent();
		
		if((arg0.getButton() == MouseEvent.BUTTON1)) {		
			for(int i=0; i < 25; i++) {
				if(avatarInventory.size() > i && jl.equals((JLabel)inventory.getComponent(i))) {
					if(avatarInventory.get(i).isEquippable()) {
						avatar.equipItem((EquippableItem) avatarInventory.get(i));
					} else {
						avatarInventory.get(i).use(avatar);
						avatar.removeItem(avatarInventory.get(i));
					}
				}
				else if(abilitiesList.size() > i && jl.equals((JLabel)abilities.getComponent(i))) {
					ability = mouseClickedInsideAbility(map, avatar, arg0);
				}
				else {
					mouseClickedInsideEquip(map,avatar,arg0);
					if(ability!=null) {
						entity = mouseClickedInsideMap(map, avatar, ability, arg0);
					}
				}
			}
			if(ability!=null && entity!= null) {
				ability.use(entity);
			}
		}
		else if((arg0.getButton() == MouseEvent.BUTTON3)) {
			for(int i=0; i<15; i++) {
				if(avatarInventory.size() > i && jl.equals((JLabel)inventory.getComponent(i))) {
					if(!map.hasItem(avatar.getLocation())) {
						TakeableItem takeable = avatar.removeItem((TakeableItem) avatarInventory.get(i));
						map.addItem(avatar.getLocation(), takeable);
					}
					else {System.out.println("Can't drop item where there's another item already!");} 
				}
			}
		}
	}
	
	/**
	 * Executes all mouseClicked events performed in the area view ports on Entity.
	 * @param map the map instance where a key has been pressed
	 * @param avatar the Avatar which executes the ability
	 * @param ability the ability that will execute
	 * @param arg0 the mouseclick event
	 * @return
	 */
	public Entity mouseClickedInsideMap(Map map, Avatar avatar, Ability ability, MouseEvent arg0) {
		Tile tiles[][] = World.getInstance().getCurrentMap().getTiles();
		JLabel jl = (JLabel) arg0.getComponent();
		
		if((arg0.getButton() == MouseEvent.BUTTON1)) {		
			for(int i = 0; i < 25; ++i) {
				if(jl.equals((JLabel)layerPane.getComponent(i))) {
					int x = i / 5;
					int y = i % 5;
					Location loc = World.getInstance().getCurrentMap().getAvatar().getLocation();
					Tile tile = tiles[loc.getY()-2+y][loc.getX()-2+x];
					Entity e = tile.getEntity();
					if(e!=null) {
						return e;
					}
				}
			}
		}
		return null;
	}
	
	/**
	 * Executes all mouseClicked events performed in the area view ports on Abilitylist.
	 * @param map the map instance where a key has been pressed
	 * @param avatar the Avatar which executes the ability
	 * @param arg0 the mouse click event
	 * @return
	 */
	public Ability mouseClickedInsideAbility(Map map, Avatar avatar, MouseEvent arg0) {
		List<Ability> abilitiesList = avatar.getOccupation().getAbilityList();
		JLabel jl = (JLabel) arg0.getComponent();
		
		if((arg0.getButton() == MouseEvent.BUTTON1)) {		
			for(int i = 0; i < abilitiesList.size(); ++i) {
				if(jl.equals((JLabel)abilities.getComponent(i))) {
					if(abilitiesList.get(i).getLevelUnlocked()<=avatar.getLevel()) {
						return abilitiesList.get(i);
					}
				}
			}
		}
		
		return null;
	}
	
	/**
	 * Executes all mouseClicked events performed in the area view ports on Equipped Inventory.
	 * @param map the map instance where a key has been pressed
	 * @param avatar the avatar which executes ability
	 * @param arg0 the mouse click event
	 */
	public void mouseClickedInsideEquip(Map map, Avatar avatar, MouseEvent arg0) {
		
		EquippedInventory avatarEquippableInventory = avatar.getEquippedInventory();
		JLabel jl = (JLabel) arg0.getComponent();
		
		if((arg0.getButton() == MouseEvent.BUTTON1) && (avatarEquippableInventory.getItemArray().length > 0 )) {		
			for(int i=0; i<5; i++) {
				if(jl.equals(equipInventory[i]) && (avatarEquippableInventory.getItem(i) != null)) {
					avatar.unEquipItem(avatarEquippableInventory.getItem(i));
				}
			}
		}
	}
	/* (non-Javadoc)
	 * @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent)
	 */
	@Override
	public void mouseEntered(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	/* (non-Javadoc)
	 * @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent)
	 */
	@Override
	public void mouseExited(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	/* (non-Javadoc)
	 * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent)
	 */
	@Override
	public void mousePressed(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	/* (non-Javadoc)
	 * @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent)
	 */
	@Override
	public void mouseReleased(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}
}
